Gopher Proxy
gopher.conman.org:70 gopher.conman.org:70/0Boston:Src:src/main_cgi.c
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/************************************************************************
*
* Copyright 2005 by Sean Conner. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Comments, questions and criticisms can be sent to: sean@conman.org
*
*************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <cgilib8/util.h>
#include "backend.h"
#include "main.h"
typedef int (*cgicmd__f)(Cgi,Blog *,struct request *);
/************************************************************************/
static int cgi_error(Blog *blog,Request *request,int level,char const *msg, ... )
{
va_list args;
char *file = NULL;
char *errmsg = NULL;
assert(level >= 400);
assert(msg != NULL);
va_start(args,msg);
vasprintf(&errmsg,msg,args);
va_end(args);
if (level >= HTTP_ISERVERERR)
syslog(LOG_ERR,"%d: %s",level,errmsg);
asprintf(&file,"%s/errors/%d.html",getenv("DOCUMENT_ROOT"),level);
if ((blog == NULL) || (freopen(file,"r",stdin) == NULL))
{
char buf[BUFSIZ];
int len = snprintf(
buf,
sizeof(buf),
"<html lang='en'>\n"
"<head>\n"
"<title>Error %d</title>\n"
"</head>\n"
"<body>\n"
"<h1>Error %d</h1>\n"
"<p>%s</p>\n"
"</body>\n"
"</html>\n"
"",
level,
level,
errmsg
);
printf(
"Status: %d\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s"
"",
level,
len,
buf
);
}
else
{
struct callback_data cbd;
assert(blog != NULL);
assert(request != NULL);
request->f.htmldump = true;
callback_init(&cbd,blog,request);
cbd.status = level;
generic_main(stdout,&cbd);
}
free(file);
free(errmsg);
/*-------------------------------------------------------------------------
; Within the context of a CGI script, the script ran fine; any error is to
; be returned via HTTP to the client.
;--------------------------------------------------------------------------*/
return 0;
}
/**********************************************************************/
static void redirect(http__e status,char const *base,char const *path)
{
assert((status == HTTP_MOVEPERM) || (status == HTTP_MOVETEMP));
assert(base != NULL);
assert(path != NULL);
char doc[BUFSIZ];
int len = snprintf(
doc,
sizeof(doc),
"<HTML>\n"
" <HEAD><TITLE>Go here</TITLE></HEAD>\n"
" <BODY><A HREF='%s%s'>%s%s</A></BODY>\n"
"</HTML>\n",
base,path,
base,path
);
printf(
"Status: %d\r\n"
"Location: %s%s\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s",
status,
base, path,
len,
doc
);
}
/**********************************************************************/
static int cmd_cgi_error(Cgi cgi,Blog *blog,Request *request)
{
(void)cgi;
return cgi_error(blog,request,HTTP_BADREQ,"Bad Request");
}
/**********************************************************************/
static int cmd_cgi_get_new(Cgi cgi,Blog *blog,Request *req)
{
struct callback_data cbd;
(void)cgi;
(void)blog;
assert(req != NULL);
req->f.edit = true;
generic_main(stdout,callback_init(&cbd,blog,req));
return 0;
}
/**********************************************************************/
static int cmd_cgi_get_show(Cgi cgi,Blog *blog,Request *req)
{
char *status;
int rc;
assert(cgi != NULL);
assert(blog != NULL);
assert(req != NULL);
status = CgiGetQValue(cgi,"status");
if (!emptynull_string(status))
{
int level = strtoul(status,NULL,10);
if (level >= 400)
return cgi_error(blog,req,level,"Error from Apache");
}
if ((emptynull_string(req->reqtumbler)) || (strcmp(req->reqtumbler,"/") == 0))
{
redirect(HTTP_MOVEPERM,blog->config.url,"");
rc = 0;
}
else
{
req->reqtumbler++;
if (tumbler_new(&req->tumbler,req->reqtumbler,&blog->first,&blog->last))
{
if (req->tumbler.redirect)
{
char *tum = tumbler_canonical(&req->tumbler);
redirect(HTTP_MOVEPERM,blog->config.url,tum);
free(tum);
return 0;
}
rc = tumbler_page(blog,req,&req->tumbler,cgi_error);
}
else
{
char filename[FILENAME_MAX];
snprintf(filename,sizeof(filename),"%s%s",getenv("DOCUMENT_ROOT"),getenv("PATH_INFO"));
if (freopen(filename,"r",stdin) == NULL)
rc = cgi_error(blog,req,HTTP_NOTFOUND,"bad request");
else
{
struct callback_data cbd;
req->f.htmldump = true;
generic_main(stdout,callback_init(&cbd,blog,req));
rc = 0;
}
}
}
return rc;
}
/********************************************************************/
static int cmd_cgi_get_today(Cgi cgi,Blog *blog,Request *req)
{
assert(cgi != NULL);
assert(blog != NULL);
assert(req != NULL);
char *tpath = CgiGetQValue(cgi,"path");
char *twhen = CgiGetQValue(cgi,"day");
if ((tpath == NULL) && (twhen == NULL))
return generate_thisday(blog,req,stdout,blog->now);
if (tpath == NULL)
return cgi_error(blog,req,HTTP_BADREQ,"bad request");
if ((twhen == NULL) || (*twhen == '\0'))
{
redirect(HTTP_MOVEPERM,blog->config.url,tpath);
return 0;
}
if (!thisday_new(&req->tumbler,twhen))
return cgi_error(blog,req,HTTP_BADREQ,"bad request");
if (req->tumbler.redirect)
{
char buf[BUFSIZ];
snprintf(
buf,
sizeof(buf),
"%s/%02d/%02d",
tpath,req->tumbler.start.month,req->tumbler.start.day
);
redirect(HTTP_MOVEPERM,blog->config.url,buf);
return 0;
}
return generate_thisday(blog,req,stdout,req->tumbler.start);
}
/**********************************************************************/
static int cmd_cgi_get_last(Cgi cgi,Blog *blog,Request *req)
{
char buf[BUFSIZ];
int len;
assert(cgi != NULL);
assert(blog != NULL);
assert(req != NULL);
char *date = CgiGetQValue(cgi,"date");
if (date == NULL)
{
len = snprintf(
buf,
sizeof(buf),
"%s%04d/%02d/%02d.%d",
blog->config.url,
blog->last.year,
blog->last.month,
blog->last.day,
blog->last.part
);
}
else
{
struct btm when;
char *p;
size_t last;
when.year = strtoul(date,&p,10); p++;
when.month = strtoul(p, &p,10); p++;
when.day = strtoul(p, &p,10);
when.part = 1;
if (btm_cmp(&when,&blog->first) < 0)
return cgi_error(blog,req,HTTP_BADREQ,"date out of range");
if (btm_cmp(&when,&blog->last) <= 0)
last = BlogLastEntry(blog,&when);
else
last = 0;
len = snprintf(
buf,
sizeof(buf),
"%s%04d/%02d/%02d.%zu",
blog->config.url,
when.year,
when.month,
when.day,
last
);
}
printf(
"Status: %d\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s",
HTTP_OKAY,
len,
buf
);
return 0;
}
/**********************************************************************/
static cgicmd__f set_m_cgi_get_command(char const *value)
{
if (emptynull_string(value))
return cmd_cgi_get_show;
else if (strcmp(value,"new") == 0)
return cmd_cgi_get_new;
else if (strcmp(value,"show") == 0)
return cmd_cgi_get_show;
else if (strcmp(value,"preview") == 0)
return cmd_cgi_get_show;
else if (strcmp(value,"today") == 0)
return cmd_cgi_get_today;
else if (strcmp(value,"last") == 0)
return cmd_cgi_get_last;
else
return cmd_cgi_error;
}
/***********************************************************************/
static void set_m_author(char *value,Request *req)
{
assert(req != NULL);
if (emptynull_string(value))
req->author = strdup(get_remote_user());
else
req->author = safe_strdup(value);
req->origauthor = strdup(req->author);
}
/************************************************************************/
static int cmd_cgi_post_new(Cgi cgi,Blog *blog,Request *req)
{
(void)cgi;
assert(blog != NULL);
assert(req != NULL);
http__e rc = entry_add(blog,req);
if (rc < HTTP_300)
{
generate_pages(blog,req);
redirect(HTTP_MOVETEMP,blog->config.url,"");
return 0;
}
else
return cgi_error(blog,req,rc,"couldn't add entry");
}
/***********************************************************************/
static int cmd_cgi_post_show(Cgi cgi,Blog *blog,Request *req)
{
struct callback_data cbd;
BlogEntry *entry;
(void)cgi;
assert(blog != NULL);
assert(req != NULL);
/*-----------------------------------------------------------------
; this routine is a mixture between entry_add() and tumbler_page().
; Perhaps some refactoring is in order at some point.
;------------------------------------------------------------------*/
callback_init(&cbd,blog,req);
entry = BlogEntryNew(blog);
if (emptynull_string(req->date))
entry->when = blog->now;
else
{
char *p;
entry->when.year = strtoul(req->date,&p,10); p++;
entry->when.month = strtoul(p, &p,10); p++;
entry->when.day = strtoul(p, &p,10);
}
entry->when.part = 1; /* doesn't matter what this is */
entry->timestamp = blog->tnow;
entry->title = strdup(req->title);
entry->class = strdup(req->class);
entry->status = strdup(req->status);
entry->author = strdup(req->author);
entry->body = strdup(req->body);
ListAddTail(&cbd.list,&entry->node);
req->f.edit = true;
generic_main(stdout,&cbd);
return 0;
}
/**********************************************************************/
static cgicmd__f set_m_cgi_post_command(char const *value)
{
assert(value != NULL);
if (emptynull_string(value))
return cmd_cgi_post_show;
else if (strcmp(value,"new") == 0)
return cmd_cgi_post_new;
else if (strcmp(value,"show") == 0)
return cmd_cgi_post_show;
else
return cmd_cgi_error;
}
/************************************************************************/
static void main_cgi_GET(Cgi cgi,Blog *blog,Request *request)
{
assert(cgi != NULL);
assert(blog != NULL);
assert(request != NULL);
request->reqtumbler = getenv("PATH_INFO");
request->f.cgiget = true;
(*set_m_cgi_get_command(CgiGetQValue(cgi,"cmd")))(cgi,blog,request);
}
/************************************************************************/
static void main_cgi_POST(Cgi cgi,Blog *blog,Request *request)
{
assert(cgi != NULL);
assert(blog != NULL);
assert(request != NULL);
set_m_author(CgiGetValue(cgi,"author"),request);
request->title = safe_strdup(CgiGetValue(cgi,"title"));
request->class = safe_strdup(CgiGetValue(cgi,"class"));
request->status = safe_strdup(CgiGetValue(cgi,"status"));
request->date = safe_strdup(CgiGetValue(cgi,"date"));
request->adtag = safe_strdup(CgiGetValue(cgi,"adtag"));
request->origbody = safe_strdup(CgiGetValue(cgi,"body"));
request->body = safe_strdup(request->origbody);
(*set_m_cgi_post_command(CgiGetValue(cgi,"cmd")))(cgi,blog,request);
}
/************************************************************************/
static void main_cgi_PUT(Cgi cgi,Blog *blog,Request *request)
{
assert(cgi != NULL);
assert(blog != NULL);
assert(request != NULL);
if (strcmp(cgi->content_type,"application/mod_blog") == 0)
{
if (mailfile_readdata(request) == 0)
{
http__e rc = entry_add(blog,request);
if (rc < HTTP_300)
{
generate_pages(blog,request);
printf("Status: %d\r\n\r\n",rc);
}
else
cgi_error(NULL,NULL,rc,"couldn't create entry");
}
else
cgi_error(NULL,NULL,HTTP_UNAUTHORIZED,"unauthorized user");
}
else
{
char const *path = getenv("PATH_INFO");
if (path == NULL)
{
syslog(LOG_ERR,"getenv(PATH_INFO) = NULL");
cgi_error(NULL,NULL,HTTP_ISERVERERR,"couldn't add file");
}
else
{
char filename[FILENAME_MAX];
FILE *fp;
snprintf(filename,sizeof(filename),"%s%s",blog->config.basedir,path);
fp = fopen(filename,"wb");
if (fp == NULL)
{
syslog(LOG_ERR,"%s: %s",filename,strerror(errno));
cgi_error(NULL,NULL,HTTP_ISERVERERR,"%s: %s",path,strerror(errno));
}
else
{
size_t bytes;
do
{
char buffer[BUFSIZ];
bytes = fread(buffer,1,sizeof(buffer),stdin);
fwrite(buffer,1,bytes,fp);
} while (bytes > 0);
fclose(fp);
printf("Status: %d\r\n\r\n",HTTP_CREATED);
}
}
}
}
/************************************************************************/
int main_cgi(void)
{
Cgi cgi = CgiNew();
if (cgi == NULL)
cgi_error(NULL,NULL,HTTP_ISERVERERR,"");
else
{
if (CgiStatus(cgi) != HTTP_OKAY)
cgi_error(NULL,NULL,CgiStatus(cgi),"processing error");
else
{
Blog *blog = BlogNew(NULL);
if (blog == NULL)
cgi_error(NULL,NULL,HTTP_ISERVERERR,"Could not instantiate the blog");
else
{
Request request;
request_init(&request);
switch(CgiMethod(cgi))
{
case HEAD:
case GET: main_cgi_GET (cgi,blog,&request); break;
case POST: main_cgi_POST(cgi,blog,&request); break;
case PUT: main_cgi_PUT (cgi,blog,&request); break;
default: cgi_error(NULL,NULL,HTTP_METHODNOTALLOWED,"Nope, not allowed."); break;
}
request_free(&request);
BlogFree(blog);
}
}
CgiFree(cgi);
}
return 0;
}
/************************************************************************/
.
you're on gopher.conman.org^70/0Boston:Src:src/main_cgi.c
back link is gopher.conman.org:70/1Boston:Src:src/